use super::{
    hdc_command::HdcCommand,
    hdc_error::{HdcError, HdcErrorKind},
};

#[derive(Debug)]
pub struct TaskMessage {
    pub channel_id: u128,
    pub command: HdcCommand,
    pub payload: Vec<u8>,
}

impl TaskMessage {
    // 将TaskMessage 转Vec
    pub fn to_vec(&self) -> Vec<u8> {
        let channel_id_byte = self.channel_id.to_be_bytes();
        let target_byte = (self.command as u64).to_be_bytes();
        let payload_len = self.payload.len() as u128;
        let payload_len_byte = payload_len.to_be_bytes();

        let mut len = channel_id_byte.len();
        len += target_byte.len();
        len += payload_len_byte.len();
        len += self.payload.len();

        let mut result = Vec::with_capacity(len);
        result.extend_from_slice(&channel_id_byte);
        result.extend_from_slice(&target_byte);
        result.extend_from_slice(&payload_len_byte);
        result.extend_from_slice(&self.payload);

        result
    }

    // 将TaskMessage转换成报文包

    pub fn to_packet(&self) -> Vec<u8> {
        let channel_id_byte = self.channel_id.to_be_bytes();
        let target_byte = (self.command as u64).to_be_bytes();
        let payload_len = self.payload.len() as u128;
        let payload_len_byte = payload_len.to_be_bytes();

        let mut len = channel_id_byte.len();
        len += target_byte.len();
        len += payload_len_byte.len();
        len += self.payload.len();

        let mut result = Vec::with_capacity(len);
        result.extend_from_slice(&channel_id_byte);
        result.extend_from_slice(&target_byte);
        result.extend_from_slice(&payload_len_byte);
        result.extend_from_slice(&self.payload);

        result
    }

    pub fn from_be_bytes(bytes: &[u8]) -> Result<Self, HdcError> {
        if bytes.len() < 40 {
            let msg = format!("Length less than the minimum length, input len: {}", bytes.len());
            log::error!("{msg}");
            return Err(HdcError::new(HdcErrorKind::HdcInvalidData, msg));
        }
        let channel_id = u128::from_be_bytes(bytes[0..16].try_into().unwrap());
        let command = u64::from_be_bytes(bytes[16..24].try_into().unwrap());
        let command = match HdcCommand::try_from(command) {
            Ok(t) => t,
            Err(err) => return Err(err),
        };
        let payload_len = u128::from_be_bytes(bytes[24..40].try_into().unwrap());
        let payload = bytes[40..].to_vec();
        if payload_len != payload.len() as u128 {
            let msg = format!("The payload length is incorrect, Expected {}, actual {}", payload_len, payload.len());
            log::error!("{msg}");
            return Err(HdcError::new(HdcErrorKind::HdcInvalidData, "".to_owned()));
        }

        Ok(Self { channel_id, command, payload })
    }
}
